package com.gc.monitor.gctask.impl;

import com.gc.gpsoo.GpsooSDK;
import com.gc.gpsoo.beans.GpsooCarData;
import com.gc.gpsoo.exception.GpsooSDKException;
import com.gc.common.entity.Car;
import com.gc.common.entity.History;
import com.gc.common.entity.HistoryPositionBusiness;
import com.gc.common.exception.ServiceException;
import com.gc.monitor.gcexception.GCMonitorException;
import com.gc.monitor.gctask.GpsooMonitor;
import com.gc.monitor.gctask.GpsooMonitorResult;
import com.gc.monitor.gctask.MonitorStatusPojo;
import com.gc.frontend.service.CarService;
import com.gc.frontend.service.HistoryPositionBusinessService;
import com.gc.frontend.service.HistoryService;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

/**
 * 历史分析任务实现类
 * Created by 瑱彬 on 2015/4/10.
 */
@Component(value = "gpsooAnalysisHistory")
@Scope("singleton")
public class GpsooAnalysisHistoryImpl implements GpsooMonitor {
    @Resource
    private CarService carService;

    @Resource
    private HistoryService historyService;

    @Resource
    private HistoryPositionBusinessService historyPositionBusinessService;


    private static Map<String, History> latestHistoryMap;

    private static Map<String, MonitorStatusPojo> latestHistoriesStatus;

    public List<GpsooCarData> getCarsInGpsoo() throws GCMonitorException {
        List<GpsooCarData> gpsooCarDatas;
        gpsooCarDatas = GpsooMonitorResult.getInstance().getMonitorResults();
        return gpsooCarDatas;

    }

    public void run() throws GCMonitorException {
        if (latestHistoryMap == null) {
            System.out.println("latestHistoryMap为null");
            initHistorys();
        }
        if (latestHistoriesStatus == null) {
            System.out.println("latestHistoriesStatus为null");
            latestHistoriesStatus = GpsooMonitorResult.getInstance().getLatestHistoriesStatus();
        }

        List<GpsooCarData> carsInGpsoo = getCarsInGpsoo();
        List<Car> carsInDb = carService.selectByDTO(null);
        try {
            checkAndSync(carsInGpsoo, carsInDb);//因为是定时任务，所以要在这里检查一下于服务器的同步情况
        } catch (ServiceException e) {
            e.printStackTrace();
            throw new GCMonitorException(e.getMessage());
        }

        for (GpsooCarData gpsooCarData : carsInGpsoo) {
            String imei = gpsooCarData.getImei();

            Boolean nowBreakStatus = (gpsooCarData.getSpeed() <= 0);

            MonitorStatusPojo latestHistoryStatus = latestHistoriesStatus.get(imei);
            latestHistoryStatus.setPosChangeStatus(
                    isPositionChange(
                            Float.parseFloat(latestHistoryStatus.getPosLng()),
                            Float.parseFloat(latestHistoryStatus.getPosLat()),
                            gpsooCarData.getLng(),
                            gpsooCarData.getLat()
                    ));
            //当前状态和上次状态的暂停标志对比
            if (nowBreakStatus.equals(latestHistoryStatus.isBreakStatus())) {
                //相等表示维持状态
                if (!latestHistoryStatus.isBreakStatus()) {
                    System.out.println("运行中");

                    //运行中
                    History history = latestHistoryMap.get(gpsooCarData.getImei());
                    if (history == null || history.getHistoryDestination() != null) {
                        history = insertHistory(gpsooCarData);
                        latestHistoryMap.put(gpsooCarData.getImei(), history);
                    }
                } else if (!latestHistoryStatus.isStayStatus()) {
                    System.out.println("暂停中");
                    //暂停中

                    if (gpsooCarData.getServerTime() - latestHistoryStatus.getTime() >= 10) {
                        //插入HistoryPosition
                        latestHistoryStatus.setStayStatus(true);
                        insertHistoryPosition(gpsooCarData);
                    }

                } else if (!latestHistoryStatus.isStopStatus()) {
                    //停止中
                    System.out.println("停止中");

                    if (gpsooCarData.getServerTime() - latestHistoryStatus.getTime() >= 300) {
                        //结束History
                        latestHistoryStatus.setStopStatus(true);
                        completeHistory(gpsooCarData);
                    }
                }
            } else {
                //不同等表示切换了状态

                if (!latestHistoryStatus.isBreakStatus()) {
                    //从运行到中断
                    System.out.println("从运行到中断");
                    History history = latestHistoryMap.get(gpsooCarData.getImei());
                    if (history == null || history.getHistoryDestination() != null) {
                        history = insertHistory(gpsooCarData);
                    }

                } else {
                    //从中断到运行
                    if (latestHistoryStatus.isStopStatus()) {
                        //停止到运行
                        System.out.println("停止到运行");
                        insertHistory(gpsooCarData);
                    }

                }
                latestHistoryStatus = GpsooMonitorResult.updateWithGpsooCarDate(latestHistoryStatus, gpsooCarData);
                latestHistoriesStatus.put(latestHistoryStatus.getImei(), latestHistoryStatus);
            }
        }
        GpsooMonitorResult.getInstance().setLatestHistoriesStatus(latestHistoriesStatus);
    }

    private boolean isPositionChange(Float statusLng, Float statusLat, Float gpsooLng, Float gpsooLat) {
        double radLat1 = statusLat.doubleValue();
        double radLat2 = gpsooLat.doubleValue();
        radLat1 = statusLng * Math.PI / 180;
        radLat2 = gpsooLng * Math.PI / 180;
        double a = radLat1 - radLat1;
        double b = statusLng * Math.PI / 180 - gpsooLng * Math.PI / 180;
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1)
                * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * 6378137.0;
        s = Math.round(s * 10000) / 10000;
        boolean flag;
        flag = s > 1000;
        return flag;
    }

    private HistoryPositionBusiness insertHistoryPosition(GpsooCarData gpsooCarData) {
        History nowHistory = latestHistoryMap.get(gpsooCarData.getImei());
        System.out.println(nowHistory);
        if (nowHistory == null) {
            nowHistory = insertHistory(gpsooCarData);
        } else if (nowHistory.getHistoryDestination() != null) {
            return null;
        }
        int historyId = nowHistory.getHistoryId();
        HistoryPositionBusiness historyPositionBusiness = new HistoryPositionBusiness();
        historyPositionBusiness.setHistoryId(historyId);
        historyPositionBusiness.setHistoryPositionTime(new Date());
        historyPositionBusiness.setHistoryPoslat(gpsooCarData.getLat() + "");
        historyPositionBusiness.setHistoryPoslong(gpsooCarData.getLng() + "");
        historyPositionBusiness.setHistoryPositionPosname(getPosName(gpsooCarData));
        historyPositionBusinessService.insertSelective(historyPositionBusiness);
        return historyPositionBusiness;
    }

    private History insertHistory(GpsooCarData gpsooCarData) {
        History history = new History();
        history.setCarImei(gpsooCarData.getImei());
        history.setHistoryBeginingPosLat(gpsooCarData.getLat() + "");
        history.setHistoryBeginingPosLong(gpsooCarData.getLng() + "");
        history.setHistoryStart(new Date());
        history.setHistoryBegining(getPosName(gpsooCarData));

        historyService.insertSelective(history);
        latestHistoryMap.put(history.getCarImei(), history);
        return history;
    }

    private History completeHistory(GpsooCarData gpsooCarData) {
        History history = latestHistoryMap.get(gpsooCarData.getImei());
        if (history == null || history.getHistoryDestination() != null) {
            return null;
        }
        history.setHistoryDestinationPosLat(gpsooCarData.getLat() + "");
        history.setHistoryDestinationPosLong(gpsooCarData.getLng() + "");
        history.setHistoryEnd(new Date());
        history.setHistoryDestination(getPosName(gpsooCarData));

        historyService.updateByPrimaryKeySelective(history);
        latestHistoryMap.put(history.getCarImei(), history);

        return history;
    }

    private void setLatestHistoryInMapByImeis(String imei) {
        History history = historyService.selectLatestHistoryByImei(imei);
        latestHistoryMap.put(imei, history);
    }

    private String getPosName(GpsooCarData gpsooCarData) {
        try {
            String address = GpsooSDK.getInstance().loadAddress(gpsooCarData.getLng() + "", gpsooCarData.getLat() + "");
            return address;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (GpsooSDKException e) {
            e.printStackTrace();
            return null;
        }
    }

    private void initHistorys() {
        latestHistoryMap = new HashMap<>();
        List<History> historys = historyService.selectLatestHistorys();
        for (History history : historys) {
            latestHistoryMap.put(history.getCarImei(), history);
        }
    }

    /**
     * 做一个简单的数据库和服务器数据监测，如果发现不同步，就调用同步方法，并返回最新的Cars
     */
    private List<Car> checkAndSync(List<GpsooCarData> carsInGpsoo, List<Car> carsInDb) throws GCMonitorException, ServiceException {
        List<String> imeisInGpsoo = new ArrayList<>();
        for (GpsooCarData carInGpsoo : carsInGpsoo) {
            imeisInGpsoo.add(carInGpsoo.getImei());
        }
        if (isNeedSynchronize(imeisInGpsoo, carsInDb)) {
            carService.synchronizeWithGpsoo();
            carsInDb = carService.selectByDTO(null);
        }

        return carsInDb;
    }

    private boolean isNeedSynchronize(List<String> imeisInGpsoo, List<Car> carsInDb) throws GCMonitorException {

        Map<String, Car> carsInDbWithKey = new HashMap<>();

        //增加Key，通过键值表来拿检索，时间复杂度为O(n)
        for (Car car : carsInDb) {
            carsInDbWithKey.put(car.getCarImei(), car);
        }

        //服务器没有的数据...我们删除他好了
        Iterator<String> carImeiInteger = carsInDbWithKey.keySet().iterator();
        String carImei;

        boolean flag = false;

        while (carImeiInteger.hasNext() && !flag) {
            carImei = carImeiInteger.next();
            if (!imeisInGpsoo.contains(carImei)) {
                flag = true;
            }
        }

        for (int i = 0; i < imeisInGpsoo.size() && !flag; i++) {
            String carInGpsooImei = imeisInGpsoo.get(i);
            if (carsInDbWithKey.get(carInGpsooImei) == null) {
                flag = true;
            }
        }
        return flag;
    }
}
